/*
 * Copyright ©2015-2021 Jaemon. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.gitee.jaemon.spring.adorner.util;

import io.gitee.jaemon.spring.adorner.AdornerConstants;
import io.gitee.jaemon.spring.adorner.type.LogLevel;

import java.io.PrintStream;
import java.time.LocalDateTime;

/**
 * 日志助手
 *
 * @author Jaemon
 * @since 1.0
 */
public class LoggerHelper {
    protected static final PrintStream console = System.out;
    protected static boolean isLogger = false;
    protected static LogLevel sysLlogLevel = LogLevel.INFO;

    /**
     * 日志输出
     *
     * @param  format
     *         A <a href="../util/Formatter.html#syntax">format string</a>
     *
     * @param  args
     *         Arguments referenced by the format specifiers in the format
     *         string.  If there are more arguments than format specifiers, the
     *         extra arguments are ignored.  The number of arguments is
     *         variable and may be zero.  The maximum number of arguments is
     *         limited by the maximum dimension of a Java array as defined by
     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
     *         The behaviour on a
     *         {@code null} argument depends on the <a
     *         href="../util/Formatter.html#syntax">conversion</a>.
     */
    public static void debug(String format, Object... args) {
        log(LogLevel.DEBUG, format, args);
    }

    /**
     * 日志输出
     *
     * @param  format
     *         A <a href="../util/Formatter.html#syntax">format string</a>
     *
     * @param  args
     *         Arguments referenced by the format specifiers in the format
     *         string.  If there are more arguments than format specifiers, the
     *         extra arguments are ignored.  The number of arguments is
     *         variable and may be zero.  The maximum number of arguments is
     *         limited by the maximum dimension of a Java array as defined by
     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
     *         The behaviour on a
     *         {@code null} argument depends on the <a
     *         href="../util/Formatter.html#syntax">conversion</a>.
     */
    public static void info(String format, Object... args) {
        log(LogLevel.INFO, format, args);
    }

    /**
     * 日志输出
     *
     * @param  format
     *         A <a href="../util/Formatter.html#syntax">format string</a>
     *
     * @param  args
     *         Arguments referenced by the format specifiers in the format
     *         string.  If there are more arguments than format specifiers, the
     *         extra arguments are ignored.  The number of arguments is
     *         variable and may be zero.  The maximum number of arguments is
     *         limited by the maximum dimension of a Java array as defined by
     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
     *         The behaviour on a
     *         {@code null} argument depends on the <a
     *         href="../util/Formatter.html#syntax">conversion</a>.
     */
    public static void warn(String format, Object... args) {
        log(LogLevel.WARN, format, args);
    }

    /**
     * 日志输出
     *
     * @param  format
     *         A <a href="../util/Formatter.html#syntax">format string</a>
     *
     * @param  args
     *         Arguments referenced by the format specifiers in the format
     *         string.  If there are more arguments than format specifiers, the
     *         extra arguments are ignored.  The number of arguments is
     *         variable and may be zero.  The maximum number of arguments is
     *         limited by the maximum dimension of a Java array as defined by
     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
     *         The behaviour on a
     *         {@code null} argument depends on the <a
     *         href="../util/Formatter.html#syntax">conversion</a>.
     */
    public static void error(String format, Object... args) {
        log(LogLevel.ERROR, format, args);
    }

    /**
     * 日志输出
     *
     * @param  format
     *         A <a href="../util/Formatter.html#syntax">format string</a>
     *
     * @param  args
     *         Arguments referenced by the format specifiers in the format
     *         string.  If there are more arguments than format specifiers, the
     *         extra arguments are ignored.  The number of arguments is
     *         variable and may be zero.  The maximum number of arguments is
     *         limited by the maximum dimension of a Java array as defined by
     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
     *         The behaviour on a
     *         {@code null} argument depends on the <a
     *         href="../util/Formatter.html#syntax">conversion</a>.
     */
    private static void log(LogLevel logLevel, String format, Object... args) {
        if (sysLlogLevel.precedence() < logLevel.precedence()) {
            return;
        }
        String msg = format(logLevel, format, args);
        logger(msg);
    }

    /**
     * 日志输出
     *
     * @param log
     *      日志信息
     */
    public static void logger(String log) {
        if (LoggerHelper.isLogger) {
            System.out.println(log);
        }
        LoggerHelper.console.println(log);
    }

    private static String format(LogLevel logLevel, String format, Object... args) {
        String source = String.format(format, args);
        return String.format(
                "%s [%s] %s",
                LocalDateTime.now().format(AdornerConstants.DATETIME_MS_FORMAT),
                logLevel.label(),
                source
        );
    }

    static {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            info("应用程序执行完毕并退出, Bye~");
            System.setOut(console);
            System.setErr(console);
        }));
    }
}